package com.wx.spring.ioc.inject;

import com.wx.spring.annotations.MyAutowired;
import com.wx.spring.constant.Constants;
import com.wx.spring.exception.SpringIocException;
import com.wx.spring.ioc.IocContainer;
import com.wx.spring.ioc.parsing.ParsingResources;
import com.wx.spring.ioc.parsing.ParsingResourcesStrategy;
import com.wx.spring.mybatis.MySqlSession;
import com.wx.spring.utils.AnnotationUtils;
import com.wx.spring.utils.ConvertUtis;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.dom4j.DocumentException;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

/**
 * @author wx
 * @Description: 注解注入bean
 * @date 2019/1/15 001518:31
 */
@Slf4j
public  class InjectAutowiredBean implements InjectBean {


    /**
     * @param contextConfigLocation
     * @description: 注解注入bean
     * @author: wx
     * @date: 2019/1/15 0015
     * @return: void
     */
    @Override
    public void injectBeanMap(String contextConfigLocation) throws SpringIocException {
        try {
            ParsingResources strategy = ParsingResourcesStrategy.getStrategy(ParsingResourcesStrategy.keyXmlScanning);
            //解析注解对象到instanceSet容器中
            strategy.parsingContent(contextConfigLocation);
            Set<String> instanceSet = IocContainer.getInstanceSet();
            if (CollectionUtils.isEmpty(IocContainer.getInstanceSet())) {
                return;
            }for (String className : instanceSet) {
                initClass(className);
            }

        } catch (DocumentException e) {
            e.printStackTrace();
            log.error("Documen解析xml异常");
            throw new RuntimeException("Documen解析xml异常");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            log.error("获取class失败");
            throw new RuntimeException("获取class失败");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param className
     * @description: 实例化操作
     * @author: wx
     * @date: 2019/1/15 0015
     * @return: void
     */
    private void initClass(String className) throws ClassNotFoundException, IllegalAccessException {
        Class<?> aClass = Class.forName(className);
        //如果类是接口，注入的对象是动态代理的对象
        if (aClass.isInterface()) {
            MySqlSession mySqlSession = new MySqlSession();
            IocContainer.getBeanMap().put(ConvertUtis.toLowerCaseFirstOne(aClass.getSimpleName()),mySqlSession.getMapper(aClass, Constants.MYBATIS_CONFIG_LOCATION));
        }
        //如果不是接口的实现类，也就是controller or Service层
        else {
            instantiatedObjet(aClass, ConvertUtis.toLowerCaseFirstOne(aClass.getSimpleName()), IocContainer.getBeanMap());
        }
        instantiatedMyAutowiredObjet(IocContainer.getBeanMap());
    }


    /**
     * @param aClass
     * @param beanKey
     * @description: 实例化对象
     * @author: wx
     * @date: 2019/1/14 0014
     * @return: void
     */
    private void instantiatedObjet(Class<?> aClass, String beanKey, Map<String, Object> map) {
        try {
            if (map.containsKey(beanKey)) {
                return;
            }
            Object object = aClass.newInstance();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields) {
                //如果有MyAutowired注解进行注入
                if (AnnotationUtils.isNotEmpty(field.getAnnotation(MyAutowired.class))) {
                    if (map.containsKey(field.getName())) {
                        field.setAccessible(true);
                        field.set(object, map.get(field.getName()));
                    } else {
                        IocContainer.getMyAutowiredSet().add(beanKey);
                    }
                }
            }
            //注入当前对象
            map.put(beanKey, object);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param map
     * @description: 注入MyAutowired注解
     * @author: wx
     * @date: 2019/1/24 0024
     * @return: void
     */
    private void instantiatedMyAutowiredObjet(Map<String, Object> map) throws IllegalAccessException {
        if (CollectionUtils.isNotEmpty(IocContainer.getMyAutowiredSet())) {
            for (String beanKey : IocContainer.getMyAutowiredSet()) {
                Object object = IocContainer.getBeanMap().get(beanKey);
                if (object == null){
                    return;
                }
                Class<?> aClass = object.getClass();
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field field : declaredFields) {
                    if (AnnotationUtils.isNotEmpty(field.getAnnotation(MyAutowired.class))) {
                        if (map.containsKey(field.getName())) {
                            field.setAccessible(true);
                            field.set(object, map.get(field.getName()));
                        }
                    }
                }
            }
        }

    }
}